package classifieurs;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import mainprogram.Statistiques;

import extraction.Categorie;
import extraction.Tweet;

public class ClassificationMultinomiale extends Classification{


	public ClassificationMultinomiale(HashMap<String, Categorie> statParClasse) {
		super(statParClasse);
	}


	/**
	 * Maps pour ranger les parametres betas - 1 par catégorie: <mot, parametre> 
	 */
	public HashMap<String, Float> mapPos = new HashMap<String, Float>();
	public HashMap<String, Float> mapNeg = new HashMap<String, Float>();
	public HashMap<String, Float> mapNeu = new HashMap<String, Float>();
	public HashMap<String, Float> mapIrr = new HashMap<String, Float>();


	/**
	 * comptes pour multinomiale
	 */
	public void modeleMultinomial(int beta_style){
		//<mot <nbDansPositive, nbDansNegative, nbDansNeutral, nbDansIrrelevant>>
		HashMap<String, ArrayList<Float>> mapMulti = new HashMap<String, ArrayList<Float>>();

		ArrayList<Float> tabMapMulti;
		HashMap<String, Integer> hashPos = positive.getMotsOcc();
		HashMap<String, Integer> hashNeg = negative.getMotsOcc();
		HashMap<String, Integer> hashNeu = neutral.getMotsOcc();
		HashMap<String, Integer> hashIrr = irrelevant.getMotsOcc();

		/*Tous les mots dans mapBinomial avec le tableau correspondant*/
		for(String mot : DataClassification.mots){
			tabMapMulti = new ArrayList<Float>();
			if (hashPos.get(mot) == null)
				tabMapMulti.add(epsilon);
			else
				tabMapMulti.add((float)hashPos.get(mot) + epsilon);
			if (hashNeg.get(mot) == null)
				tabMapMulti.add(epsilon);
			else
				tabMapMulti.add((float)hashNeg.get(mot));
			if (hashNeu.get(mot) == null)
				tabMapMulti.add(epsilon);
			else
				tabMapMulti.add((float)hashNeu.get(mot) + epsilon);
			if (hashIrr.get(mot) == null)
				tabMapMulti.add(epsilon);
			else
				tabMapMulti.add((float)hashIrr.get(mot) + epsilon);

			mapMulti.put(mot, tabMapMulti);
		}
		/**/

		Float betaPos;
		Float betaNeg;
		Float betaNeu;
		Float betaIrr;
		for (Entry<String, ArrayList<Float>> entry : mapMulti.entrySet()){
			//occurence de ce mot (dans la classe) sur nb tot occurence dans classe
			if (beta_style == 0) {
				betaPos = entry.getValue().get(0)/ positive.getOccurencesTotales();
				betaNeg = entry.getValue().get(1)/ negative.getOccurencesTotales();
				betaNeu = entry.getValue().get(2)/ neutral.getOccurencesTotales();
				betaIrr = entry.getValue().get(3)/ irrelevant.getOccurencesTotales();
			}
			else{
				betaPos = entry.getValue().get(0)/ positive.getListeTweet().size();
				betaNeg = entry.getValue().get(1)/ negative.getListeTweet().size();
				betaNeu = entry.getValue().get(2)/ neutral.getListeTweet().size();
				betaIrr = entry.getValue().get(3)/ irrelevant.getListeTweet().size();

			}
			mapPos.put(entry.getKey(), betaPos );
			mapNeg.put(entry.getKey(), betaNeg );
			mapNeu.put(entry.getKey(), betaNeu );
			mapIrr.put(entry.getKey(), betaIrr );
		}
	}



	/**
	 * Calcul pourcentage erreur test concerné
	 * 1 = test, 9=apprentissage
	 * Répétition 10 fois en changeant bloc test
	 */
	public float validationCroisee(){
		ArrayList<Tweet> listeTweet = test_positive.getListeTweet();
		listeTweet.addAll(test_negative.getListeTweet());
		listeTweet.addAll(test_neutral.getListeTweet());
		listeTweet.addAll(test_irrelevant.getListeTweet());


		int ok=0;
		int nonok=0;
		for (Tweet t : listeTweet){
			//System.out.println("tweet choisi : "+t.getSentiment()+" --> " +t.getTweetText());
			float vraisPos = calculVraisemblanceMultinomial(t, mapPos);
			float vraisNeg = calculVraisemblanceMultinomial(t, mapNeg);
			float vraisNeu = calculVraisemblanceMultinomial(t, mapNeu);
			float vraisIrr = calculVraisemblanceMultinomial(t, mapIrr);
			float max;

			max = (vraisNeg > vraisPos) ? vraisNeg : vraisPos;
			max = (vraisNeu > max) ? vraisNeu : max;
			max = (vraisIrr > max) ? vraisIrr : max;

			String max_string = null;
			if (max==vraisPos) max_string = "positive";
			else if (max==vraisNeg) max_string = "negative";
			else if (max==vraisNeu) max_string = "neutral";
			else if (max==vraisIrr) max_string = "irrelevant";

			if(t.getSentiment().equals("test_"+max_string)){
				ok++;
			}
			else{
				nonok++;
			}
		}
		System.out.println("ok="+ok+" et nonok="+nonok+" --> pourcentage nonok : "+ ((float)nonok/(ok+nonok)));
		return ((float)nonok/(ok+nonok));
	}
	
	/**
	 * Calcul vraisemblance pour 1 doc
	 * @param tweet : document considéré
	 * @param mapCategorie : liste des mots du dico pour cette classe avec leurs parametres respectifs
	 * @return inference : <0, plus elle est proche de 0, plus le Tweet est proche de la catégorie concernée
	 */
	public float calculVraisemblanceMultinomial (Tweet tweet, HashMap<String, Float> mapCategorie){
		float vraisemblance = 0;
		ArrayList<String> tabMotsDoc = 	tweet.getMotsTweetText();
		//parcour map dico
		for (Entry<String, Float> entry : mapCategorie.entrySet()){
			//mot présent dans doc ?
			if (tabMotsDoc.contains(entry.getKey())){
				//vraisemblance 
				vraisemblance += Math.log(entry.getValue());
			}
		}
		return vraisemblance;
	}
	
	public static void main(String[] args) {
		Statistiques stats = new Statistiques();
		DataClassification d = new DataClassification();
		try {
			stats.analyseFichier("./train.txt"); //remplit statParClasse (analyse avec extraction)
			d.mots_significatifs = stats.getMotsMoinsSignificatifs(); //remplit la map mots_significatifs
			//d.mots_significatifs = stats.getMotsPlusSignificatifs();
		
			//remplissage des map
			d.analyseFichier("./trainMelange.txt");
			Classification cl;
			float err = 0;

			for (int i=0; i<10; i++){
				cl = new ClassificationMultinomiale(d.mapStatParClass.get(i));
				((ClassificationMultinomiale) cl).modeleMultinomial(0); //style beta en param
				err += ((ClassificationMultinomiale) cl).validationCroisee();
			}
			System.out.println("erreur moyenne : "+ (float)err/10);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
